Skip to content

fix(integrations): stop frontmatter injection gluing onto a missing trailing newline - #4570

Open
Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/frontmatter-flag-no-trailing-newline
Open

Noor-ul-ain001 wants to merge 1 commit into
github:mainfrom
Noor-ul-ain001:fix/frontmatter-flag-no-trailing-newline

Conversation

@Noor-ul-ain001

Copy link
Copy Markdown
Contributor

Summary

_inject_frontmatter_flag() in ClaudeIntegration/VibeIntegration/AlquimiaAIIntegration detects the closing --- line's existing EOL and reuses it when injecting a new frontmatter key. When that --- is the file's last line with no trailing newline, the injected text is appended with no newline separator at all, producing user-invocable: true--- instead of a clean, separately-lined ---.

This corrupts the frontmatter (the closing delimiter is no longer alone on its own line), and since post_process_skill_content() chains multiple calls (user-invocable, then disable-model-invocation, then any fork-context keys), the second call's pre-scan can no longer find a second --- line at all — so every subsequent key injection is silently dropped, not just corrupted.

post_process_skill_content() runs on content from "external skill generators (presets, extensions)" per its own docstring, so a trailing newline after the closing delimiter isn't guaranteed.

>>> ClaudeIntegration._inject_frontmatter_flag("---\nname: x\n---", "user-invocable")
'---\nname: x\nuser-invocable: true---'          # corrupted delimiter
>>> # a second call on that output:
>>> ClaudeIntegration._inject_frontmatter_flag(_, "disable-model-invocation", "false")
'---\nname: x\nuser-invocable: true---'           # unchanged -- silently dropped

DroidIntegration's own copy of this exact helper already emits an unconditional \n instead of detecting/reusing the existing EOL, avoiding this bug entirely. Ported that fix to the other three implementations that share the same code.

Changes

  • src/specify_cli/integrations/claude/__init__.py, vibe/__init__.py, alquimia/__init__.py: _inject_frontmatter_flag now always emits f"{key}: {value}\n", matching DroidIntegration.
  • Added a regression test to each affected integration's test file, covering both the single-call corruption and the chained-calls silent-drop.

Test plan

  • ruff check . clean
  • New tests fail against the pre-fix code (verified via test-the-test) and pass with the fix
  • Full tests/integrations/test_integration_{claude,vibe,alquimia,droid}.py suite: 185 passed, 1 pre-existing/unrelated skip

…railing newline

ClaudeIntegration/VibeIntegration/AlquimiaAIIntegration's
_inject_frontmatter_flag() detected the closing "---" line's existing
EOL and reused it when injecting a new key -- so when that "---" was
the file's last line with no trailing newline, the injected text was
appended with no newline at all, producing "user-invocable: true---"
instead of a properly separated line. This corrupts the frontmatter
(the closing delimiter is no longer alone on its own line) and, since
post_process_skill_content() chains multiple injection calls, silently
drops every subsequent key: a second call's pre-scan can no longer find
a second "---" line to inject before, so e.g.
"disable-model-invocation: false" is never added at all.

post_process_skill_content() runs on content from "external skill
generators (presets, extensions)" per its own docstring, so a trailing
newline after the closing delimiter isn't guaranteed.

DroidIntegration's own copy of this helper already emits an
unconditional "\n" instead of detecting/reusing the existing EOL,
exactly avoiding this bug -- ported that fix to the other three
implementations. Added a regression test to each of the three affected
integrations' test files, covering both the single-call corruption and
the chained-calls silent-drop.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U74yBbvVQCPwB7Ed8Dzeu6
@mnriem mnriem added the triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review label Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-nice-to-have Verdict: evidence-backed fix or greenlit feature — land after review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants